/**
 * infer 是 inference 的缩写，意为推断，如 infer R 中 R 就表示 待推断的类型。 
 * infer 只能在 条件类型 中使用，因为实际上仍然需要 类型结构 是一致的
 * 
 * 通过 infer 关键字来在 条件类型 中提取 类型的某一部分信息
 * 
 * 条件类型 在 泛型的基础 上支持了基于 类型信息的动态条件判断，但无法直接消费 填充类型信息，
 * 而 infer 关键字则为它补上了这一部分的能力，
*/

//1、结合 infer、泛型、联合类型 与 数组 使用：
type Swap<T extends any[]> = T extends [infer A, infer B] ? A | B : T;
type SwapResult1 = Swap<[1, 'hanxuming']>; // 符合元组结构，抽离成 字面量联合类型 1 | 'hanxuming'
type SwapResult2 = Swap<[1, 2, 3]>; // 不符合结构，没有发生替换，仍是 [1, 2, 3]
//还可以结合 rest 操作符来处理 任意长度数组 的情况
type ExtractStartAndEnd<T extends any[]> = T extends [
    infer Start,
    ...infer Left,
    infer End
]
    ? [End, ...Left, Start]
    : T;
type ExtractStartAndEndA = ExtractStartAndEnd<[1, 2, 3, 4, 5]>; //调换首尾：[5, 2, 3, 4, 1]

//2、infer 结构也可以是接口
// 提取对象的属性类型
type PropType<T, K extends keyof T> = T extends { [Key in K]: infer R }
    ? R
    : never;
type PropTypeResult1 = PropType<{ name: string }, 'name'>; // string
type PropTypeResult2 = PropType<{ name: string; age: number }, 'name' | 'age'>; // string | number
// 反转键名与键值
type ReverseKeyValue<T extends Record<string, unknown>> = T extends Record<infer K, infer V> ? Record<V & string, K> : never
type ReverseKeyValueResult1 = ReverseKeyValue<{ "key": "value" }>; // { "value": "key" }


//3、infer 结构也可以是函数，比如 提取函数返回值类型
type Func = (...args: any[]) => any;
type FunctionReturnType<T extends Func> = T extends (...args: any[]) => infer R ? R : never;
type StringResult = FunctionReturnType<() => string>; //string


//4、infer 结构还可以是 Promise 结构！
type PromiseValue<T> = T extends Promise<infer V> ? V : T;
type PromiseValueResult1 = PromiseValue<Promise<number>>; // number
type PromiseValueResult2 = PromiseValue<number>; // number，但并没有发生提取


//5、infer 关键字也经常被使用在嵌套的场景中
type PromiseValueA<T> = T extends Promise<infer V>
    ? V extends Promise<infer N>
    ? N
    : V
    : T;
type PromiseValueResult3 = PromiseValueA<Promise<Promise<boolean>>>; // boolean


//6、使用递归来处理任意嵌套深度：
type PromiseValueB<T> = T extends Promise<infer V> ? PromiseValueB<V> : T;
type PromiseValueResult4 = PromiseValueB<Promise<Promise<Promise<Promise<Number>>>>>; //Number

//export {}：解决“无法重新声明块范围变量”错误提示问题
export { }